package com.yiyuan.app.service.impl;

import cn.hutool.core.date.LocalDateTimeUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.guaike.core.entity.exception.ApiException;
import com.guaike.core.entity.result.Result;
import com.guaike.core.redis.context.ApiContext;
import com.guaike.core.utils.HttpUtil;
import com.guaike.core.utils.ListUtil;
import com.yiyuan.app.config.RequestUrlProperties;
import com.yiyuan.app.entity.constant.MQTTTopicConstant;
import com.yiyuan.app.entity.message.BackedMessage;
import com.yiyuan.app.entity.message.BarrageMessage;
import com.yiyuan.app.mqtt.MQTTProducer;
import com.yiyuan.app.service.BaseUtilService;
import com.yiyuan.app.service.PlayService;
import com.yiyuan.app.dao.*;
import com.yiyuan.app.entity.enums.*;
import com.yiyuan.app.entity.param.*;
import com.yiyuan.app.entity.po.*;
import com.yiyuan.app.entity.result.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@AllArgsConstructor
public class PlayServiceImpl implements PlayService {

    private final GConfRoomDAO gConfRoomDAO;
    private final GConfRoomDeviceDAO gConfRoomDeviceDAO;
    private final MRecordProductLookDAO mRecordProductLookDAO;
    private final UAppUserDAO uAppUserDAO;
    private final UAppUserEquityDAO uAppUserEquityDAO;
    private final GRecordGameDAO gRecordGameDAO;
    private final GConfDeviceDAO gConfDeviceDAO;
    private final MRecordOccupyDAO mRecordOccupyDAO;
    private final GRecordRoomWatchDAO gRecordRoomWatchDAO;
    private final MQTTProducer messageProducer;
    private final BaseUtilService baseUtilService;
    private final DDetailsPineconeDAO dDetailsPineconeDAO;
    private final MRecordBattlePushCoinsDAO mRecordBattlePushCoinsDAO;
    private final MRecordBattleArcadeMachineDAO mRecordBattleArcadeMachineDAO;
    private final MRecordBattleRecreationDAO mRecordBattleRecreationDAO;
    private final MRankBattlePushCoinsDAO mRankBattlePushCoinsDAO;
    private final MRankBattleArcadeMachineDAO mRankBattleArcadeMachineDAO;
    private final MRankBattleRecreationDAO mRankBattleRecreationDAO;
    private final MRecordTaskDailyDAO mRecordTaskDailyDAO;
    private final GRoomRepairRecordDAO gRoomRepairRecordDAO;
    private final GConfRoomPrizeDAO gConfRoomPrizeDAO;
    private final GConfPrizeItemDAO gConfPrizeItemDAO;
    private final GRecordPrizeDAO gRecordPrizeDAO;
    private final GConfPrizeDAO gConfPrizeDAO;
    private final RequestUrlProperties requestUrlProperties;


    @Override
    public Result<List<BaseRoomVO>> roomList(RoomListDTO param) {
        List<BaseRoomVO> vos = new ArrayList<>();
        if (RoomTypeEnum.push_coins.getCode().equals(param.getRoomType())) {
            if (param.getRankType().equals(RoomRankEnum.default_rank.getCode())) {
                vos = gConfRoomDAO.findPushCoinsList(param.getMultipleType());
            } else {
                vos = gConfRoomDAO.findPushCoinsListFreeTopping(param.getMultipleType());
            }
            vos.forEach(vo -> {
                long lookPersonCount = gRecordRoomWatchDAO.getLookPersonCount(vo.getId());
                vo.setWatchCount((int) lookPersonCount);
                if (lookPersonCount > 0) {
                    List<GRecordRoomWatchPO> watchPOS = gRecordRoomWatchDAO.getNewThreePerson(vo.getId());
                    List<Long> userIds = watchPOS.stream().map(GRecordRoomWatchPO::getUserId).collect(Collectors.toList());
                    List<UAppUserPO> userPOS = uAppUserDAO.findByIdList(userIds);
                    List<String> images = userPOS.stream().map(UAppUserPO::getAvatarurl).collect(Collectors.toList());
                    vo.setWatchImageList(images);
                }
            });
        } else {
            if (RoomTypeEnum.arcade_machine.getCode().equals(param.getRoomType())) {
                List<GConfRoomPO> pos = gConfRoomDAO.findRoomList(param.getRoomType(), param.getMultipleType());
                List<BaseRoomVO> finalVos = vos;
                pos.forEach(po -> {
                    BaseRoomVO vo = new BaseRoomVO();
                    BeanUtils.copyProperties(po, vo);
                    long playing = gRecordGameDAO.countRoomPlaying(vo.getId());
                    if (playing > 0) {
                        long positionNum = gConfRoomDeviceDAO.findCount(GConfRoomDevicePO::getRoomId, vo.getId());
                        vo.setPositionNum((int) positionNum);
                        vo.setPlayNum((int) playing);
                        vo.setRoomStatus(RoomStatusEnum.playing.getCode());
                    } else {
                        vo.setRoomStatus(RoomStatusEnum.free.getCode());
                    }
                    finalVos.add(vo);
                });
                if (param.getRankType().equals(RoomRankEnum.default_rank.getCode())) {
                    vos = finalVos;
                } else {
                    vos = finalVos.stream().sorted(Comparator.comparing(BaseRoomVO::getRoomStatus)).collect(Collectors.toList());
                }
            } else {
                if (param.getRankType().equals(RoomRankEnum.default_rank.getCode())) {
                    vos = gConfRoomDAO.findArcadeMachineList(param.getMultipleType(), param.getRoomType());
                } else {
                    vos = gConfRoomDAO.findArcadeMachineListFreeTopping(param.getMultipleType(), param.getRoomType());
                }
            }
        }
        return Result.success().data(vos).build();
    }

    @Override
    public Result<RoomVO> intoRoom(Long roomId) throws IOException {
        GConfRoomPO roomPO = gConfRoomDAO.findById(roomId);
        if (Objects.isNull(roomPO)) {
            return Result.failure().message("房间不存在").build();
        }
        RoomVO vo = new RoomVO();
        AppUser currentUser = ApiContext.getCurrentUser();
        if (roomPO.getRoomType().equals(RoomTypeEnum.push_coins.getCode())) {
            GConfRoomDevicePO roomDevicePO = gConfRoomDeviceDAO.findOne(GConfRoomDevicePO::getRoomId, roomId);
            MRecordProductLookPO lookPO = mRecordProductLookDAO.findEnableOne(roomId, roomDevicePO.getPositionNo(), EquityEnum.forbid_look.getCode());
            if (Objects.nonNull(lookPO) && !lookPO.getUserId().equals(currentUser.getUserId())) {
                return Result.failure().message("该房间禁止围观").build();
            }
        }
        UAppUserEquityPO equityPO = uAppUserEquityDAO.findOne(UAppUserEquityPO::getUserId, currentUser.getUserId());
        UAppUserPO userPO = uAppUserDAO.findById(currentUser.getUserId());
        Boolean goIntoRoom = baseUtilService.checkIsGoIntoRoom(userPO, equityPO, roomPO);
        vo.setIsGoInto(goIntoRoom);
        if (vo.getIsGoInto()) {
            GRecordRoomWatchPO watchPO = gRecordRoomWatchDAO.findUserOne(currentUser.getUserId(), roomId);
            if (Objects.isNull(watchPO)) {
                watchPO = new GRecordRoomWatchPO();
                watchPO.setRoomId(roomId);
                watchPO.setUserId(currentUser.getUserId());
                gRecordRoomWatchDAO.save(watchPO);
            }
            BeanUtils.copyProperties(roomPO, vo);
            List<BaseDeviceVO> deviceList = new ArrayList<>();
            if (roomPO.getRoomType().equals(RoomTypeEnum.push_coins.getCode())) {
                List<GRecordGamePO> gamePOS = gRecordGameDAO.findRoomPlaying(vo.getId());
                BaseDeviceVO deviceVO = new BaseDeviceVO();
                GConfRoomDevicePO roomDevicePO = gConfRoomDeviceDAO.findOne(GConfRoomDevicePO::getRoomId, roomId);
                GConfDevicePO devicePO = gConfDeviceDAO.findById(roomDevicePO.getDeviceId());
                BeanUtils.copyProperties(devicePO, deviceVO);
                deviceVO.setPositionNo(roomDevicePO.getPositionNo());
                if (!devicePO.getStatus()) {
                    vo.setRoomStatus(RoomStatusEnum.offline.getCode());
                    deviceVO.setStatus(RoomStatusEnum.offline.getCode());
                } else if (CollectionUtils.isNotEmpty(gamePOS)) {
                    if (gamePOS.get(0).getUserId().equals(currentUser.getUserId())) {
                        vo.setRoomStatus(RoomStatusEnum.myself.getCode());
                        deviceVO.setStatus(RoomStatusEnum.myself.getCode());
                        long seconds = ChronoUnit.SECONDS.between(LocalDateTime.now(), gamePOS.get(0).getEndTime());
                        deviceVO.setCountdown((int) seconds);
                    } else {
                        vo.setRoomStatus(RoomStatusEnum.playing.getCode());
                        deviceVO.setStatus(RoomStatusEnum.playing.getCode());
                    }
                    UAppUserPO appUserPO = uAppUserDAO.findById(gamePOS.get(0).getUserId());
                    UAppUserEquityPO userEquityPO = uAppUserEquityDAO.findOne(UAppUserEquityPO::getUserId, gamePOS.get(0).getUserId());
                    deviceVO.setUserId(appUserPO.getId());
                    deviceVO.setNickname(appUserPO.getNickname());
                    deviceVO.setAvatarurl(appUserPO.getAvatarurl());
                    deviceVO.setMyVipLevel(userEquityPO.getVipGrade());
                } else {
                    if (Objects.nonNull(devicePO.getRepairTime())) {
                        vo.setRoomStatus(RoomStatusEnum.repairing.getCode());
                        deviceVO.setStatus(RoomStatusEnum.repairing.getCode());
                    } else {
                        vo.setRoomStatus(RoomStatusEnum.free.getCode());
                        deviceVO.setStatus(RoomStatusEnum.free.getCode());
                    }
                }
                deviceList.add(deviceVO);
            } else {
                List<GConfRoomDevicePO> roomDevicePOS = gConfRoomDeviceDAO.findList(GConfRoomDevicePO::getRoomId, roomId, GConfRoomDevicePO::getPositionNo, Boolean.TRUE);
                roomDevicePOS.forEach(roomDevicePO -> {
                    BaseDeviceVO deviceVO = new BaseDeviceVO();
                    deviceVO.setIsRotate(roomDevicePO.getIsRotate());
                    GConfDevicePO devicePO = gConfDeviceDAO.findById(roomDevicePO.getDeviceId());
                    BeanUtils.copyProperties(devicePO, deviceVO);
                    deviceVO.setPositionNo(roomDevicePO.getPositionNo());
                    String requestUrl = requestUrlProperties.getCheckTcpSocketUrl() + "?deviceNo=" + devicePO.getSerialNumber();
                    Object request = HttpUtil.getRequest(requestUrl, "utf-8");
                    if (Objects.isNull(request)) {
                        deviceVO.setStatus(RoomStatusEnum.offline.getCode());
                    }
                    JSONObject jsonObject = JSON.parseObject(request.toString());
                    if (!jsonObject.getBoolean("success")) {
                        throw new ApiException(jsonObject.getString("message"));
                    }
                    Boolean data = jsonObject.getBoolean("data");
                    if (!data) {
                        deviceVO.setStatus(RoomStatusEnum.offline.getCode());
                    }
                    if (Objects.isNull(deviceVO.getStatus())) {
                        GRecordGamePO gamePO = gRecordGameDAO.findRoomPlaying(roomId, roomDevicePO.getPositionNo());
                        if (Objects.isNull(gamePO)) {
                            deviceVO.setStatus(RoomStatusEnum.free.getCode());
                        } else {
                            if (gamePO.getUserId().equals(currentUser.getUserId()) && !gamePO.getSettleStatus()) {
                                vo.setRoomStatus(RoomStatusEnum.myself.getCode());
                                deviceVO.setStatus(RoomStatusEnum.myself.getCode());
                                long seconds = ChronoUnit.SECONDS.between(LocalDateTime.now(), gamePO.getFinallyCoinTime());
                                deviceVO.setCountdown(seconds < 0 ? 0 : (int) seconds);
                            } else {
                                vo.setRoomStatus(RoomStatusEnum.playing.getCode());
                                deviceVO.setStatus(RoomStatusEnum.playing.getCode());
                            }
                            UAppUserPO appUserPO = uAppUserDAO.findById(gamePO.getUserId());
                            UAppUserEquityPO userEquityPO = uAppUserEquityDAO.findOne(UAppUserEquityPO::getUserId, gamePO.getUserId());
                            deviceVO.setUserId(appUserPO.getId());
                            deviceVO.setNickname(appUserPO.getNickname());
                            deviceVO.setAvatarurl(appUserPO.getAvatarurl());
                            deviceVO.setMyVipLevel(userEquityPO.getVipGrade());
                        }
                    }
                    deviceList.add(deviceVO);
                });
            }
            vo.setDeviceList(deviceList);
            long lookPersons = gRecordRoomWatchDAO.findCount(GRecordRoomWatchPO::getRoomId, roomId);
            vo.setLookPersons((int) lookPersons);
            BarrageMessage message = new BarrageMessage();
            message.setRoomId(roomId);
            message.setNickName(userPO.getNickname());
            message.setAvatarurl(userPO.getAvatarurl());
            message.setVipLevel(equityPO.getVipGrade());
            message.setContent("进入房间");
            messageProducer.sendMessage(MQTTTopicConstant.ROOM_BARRAGE_KEY, JSON.toJSONString(message));
        }
        return Result.success().data(vo).build();
    }

    @Override
    @Transactional
    public Result<Boolean> startGame(StartGameDTO param) {
        GConfRoomPO roomPO = gConfRoomDAO.findById(param.getRoomId());
        if (Objects.isNull(roomPO)) {
            return Result.failure().message("房间不存在").build();
        }
        GConfRoomDevicePO roomDevicePO = gConfRoomDeviceDAO.findOne(param.getRoomId(), param.getPositionNo());
        if (Objects.isNull(roomDevicePO)) {
            return Result.failure().message("该房间不存在此机位").build();
        }
        GConfDevicePO devicePO = gConfDeviceDAO.findById(roomDevicePO.getDeviceId());
        if (Objects.nonNull(devicePO.getRepairTime())) {
            return Result.failure().message("该机位维修中，不能游戏").build();
        }
        if (!devicePO.getStatus()) {
            return Result.failure().message("该机位以离线，不能游戏").build();
        }
        AppUser currentUser = ApiContext.getCurrentUser();
        UAppUserEquityPO equityPO = uAppUserEquityDAO.findOne(UAppUserEquityPO::getUserId, currentUser.getUserId());
        if (equityPO.getPinecone() < roomPO.getMultipleValue()) {
            return Result.failure().message("松果不足，请充值后再开始游戏").build();
        }
        UAppUserPO userPO = uAppUserDAO.findById(currentUser.getUserId());
        Boolean goIntoRoom = baseUtilService.checkIsGoIntoRoom(userPO, equityPO, roomPO);
        if (!goIntoRoom) {
            return Result.failure().message("你不能进入此房间游戏").build();
        }
        String checkGaming = param.getRoomId() + param.getPositionNo();
        Long gameId = baseUtilService.checkGaming(checkGaming, userPO.getId(), param.getRoomId(), param.getPositionNo());
        if (Objects.isNull(gameId)) {
            return Result.failure().message("该机位有人在玩，请您更换新机位").build();
        }
        if (!roomPO.getRoomType().equals(RoomTypeEnum.push_coins.getCode())) {
            String requestUrl = requestUrlProperties.getCheckTcpSocketUrl() + "?deviceNo=" + devicePO.getSerialNumber();
            Object request = HttpUtil.getRequest(requestUrl, "utf-8");
            if (Objects.isNull(request)) {
                return Result.failure().message("设备离线，请稍后再试").build();
            }
            JSONObject jsonObject = JSON.parseObject(request.toString());
            if (!jsonObject.getBoolean("success")) {
                return Result.failure().message(jsonObject.getString("message")).build();
            }
            Boolean data = jsonObject.getBoolean("data");
            if (!data) {
                return Result.failure().message("设备离线，请稍后再试").build();
            }
        }
        // 判断是否有正在挑战中的任务进行游戏关联
        if (roomPO.getRoomType().equals(RoomTypeEnum.push_coins.getCode())) {
            MRecordBattlePushCoinsPO latestBattle = mRecordBattlePushCoinsDAO.findLatestBattleByUserId(currentUser.getUserId());
            if (Objects.nonNull(latestBattle) && Objects.isNull(latestBattle.getGameId())) {
                latestBattle.setGameId(gameId);
                mRecordBattlePushCoinsDAO.updateById(latestBattle);
            }
        } else if (roomPO.getRoomType().equals(RoomTypeEnum.arcade_machine.getCode())) {
            MRecordBattleArcadeMachinePO latestBattle = mRecordBattleArcadeMachineDAO.findLatestBattleByUserId(currentUser.getUserId());
            if (Objects.nonNull(latestBattle) && Objects.isNull(latestBattle.getGameId())) {
                latestBattle.setGameId(gameId);
                mRecordBattleArcadeMachineDAO.updateById(latestBattle);
            }
        } else {
            MRecordBattleRecreationPO latestBattle = mRecordBattleRecreationDAO.findLatestBattleByUserId(currentUser.getUserId());
            if (Objects.nonNull(latestBattle) && Objects.isNull(latestBattle.getGameId())) {
                latestBattle.setGameId(gameId);
                mRecordBattleRecreationDAO.updateById(latestBattle);
            }
        }
        return Result.success().data(Boolean.TRUE).build();
    }

    @Override
    public Result<Boolean> checkCanPlay(Long roomId, String positionNo) {
        AppUser currentUser = ApiContext.getCurrentUser();
        GRecordGamePO gamePO = gRecordGameDAO.findUserPlaying(currentUser.getUserId(), roomId, positionNo);
        if (Objects.isNull(gamePO)) {
            return Result.success().data(Boolean.FALSE).build();
        }
        return Result.success().data(Boolean.TRUE).build();
    }


    @Override
    @Transactional
    public Result<Boolean> exitGame(ExitGameDTO param) throws Exception {
        GConfRoomPO roomPO = gConfRoomDAO.findById(param.getRoomId());
        if (Objects.isNull(roomPO)) {
            return Result.failure().message("房间不存在").build();
        }
        AppUser currentUser = ApiContext.getCurrentUser();
        List<GRecordGamePO> gamePOS = gRecordGameDAO.findGamingList(roomPO.getId(), currentUser.getUserId());
        if (CollectionUtils.isNotEmpty(gamePOS)) {
            log.info("退出房间进行结算");
            for (GRecordGamePO gamePO : gamePOS) {
                GRecordGamePO lock = gRecordGameDAO.findByIdLock(gamePO.getId());
                if (roomPO.getRoomType().equals(RoomTypeEnum.push_coins.getCode())) {
                    if (Objects.nonNull(lock.getRecordOccupyId())) {
                        //结算推币机包机
                        MRecordOccupyPO occupyPO = mRecordOccupyDAO.findById(lock.getRecordOccupyId());
                        if (!occupyPO.getIsSettle()) {
                            Integer pinecone = occupyPO.getCurrentPinecone() > occupyPO.getPinecone() ? occupyPO.getCurrentPinecone() : occupyPO.getPinecone();
                            uAppUserEquityDAO.addPinecone(currentUser.getUserId(), pinecone);
                            DDetailsPineconePO myDetail = new DDetailsPineconePO();
                            myDetail.setUserId(currentUser.getUserId());
                            myDetail.setLabelType(LabelTypeEnum.occupy.getCode());
                            myDetail.setDetailsType(DetailsTypeEnum.income.getCode());
                            myDetail.setPinecone(pinecone);
                            myDetail.setRemark("包机记录ID:" + lock.getRecordOccupyId());
                            dDetailsPineconeDAO.save(myDetail);
                            mRecordOccupyDAO.updateSettleEnd(lock.getRecordOccupyId());
                            gRecordGameDAO.updateOccupyGameEnd(gamePO.getId());
                        }
                    } else {
                        gRecordGameDAO.updateGameEnd(gamePO.getId());
                    }
                } else {
//                    baseUtilService.settleMachine(lock.getDeviceId());
                    messageProducer.sendIoMessage(MQTTTopicConstant.SEND_SETTLE_MACHINE, String.valueOf(gamePO.getId()), 1);
                }
            }

        }
        gRecordRoomWatchDAO.deleteUserWatch(currentUser.getUserId(), roomPO.getId());
        return Result.success().data(Boolean.TRUE).build();
    }

    @Override
    @Transactional
    public Result<Boolean> exitOccupyGame(ExitGameDTO param) {
        GConfRoomPO roomPO = gConfRoomDAO.findById(param.getRoomId());
        if (Objects.isNull(roomPO)) {
            return Result.failure().message("房间不存在").build();
        }
        if (!roomPO.getRoomType().equals(RoomTypeEnum.push_coins.getCode())) {
            return Result.failure().message("仅推币机可提前结束畅玩").build();
        }
        GConfRoomDevicePO roomDevicePO = gConfRoomDeviceDAO.findOne(GConfRoomDevicePO::getRoomId, param.getRoomId());
        AppUser currentUser = ApiContext.getCurrentUser();
        List<GRecordGamePO> gamePOS = gRecordGameDAO.findGamingList(roomPO.getId(), currentUser.getUserId());
        if (CollectionUtils.isNotEmpty(gamePOS)) {
            for (GRecordGamePO gamePO : gamePOS) {
                GRecordGamePO lock = gRecordGameDAO.findByIdLock(gamePO.getId());
                if (Objects.nonNull(lock.getRecordOccupyId())) {
                    //结算推币机包机
                    MRecordOccupyPO occupyPO = mRecordOccupyDAO.findById(lock.getRecordOccupyId());
                    if (!occupyPO.getIsSettle()) {
                        Integer pinecone = occupyPO.getCurrentPinecone() > occupyPO.getPinecone() ? occupyPO.getCurrentPinecone() : occupyPO.getPinecone();
                        uAppUserEquityDAO.addPinecone(currentUser.getUserId(), pinecone);
                        DDetailsPineconePO myDetail = new DDetailsPineconePO();
                        myDetail.setUserId(currentUser.getUserId());
                        myDetail.setLabelType(LabelTypeEnum.occupy.getCode());
                        myDetail.setDetailsType(DetailsTypeEnum.income.getCode());
                        myDetail.setPinecone(pinecone);
                        myDetail.setRemark("包机记录ID:" + lock.getRecordOccupyId());
                        dDetailsPineconeDAO.save(myDetail);
                        mRecordOccupyDAO.updateSettleEnd(lock.getRecordOccupyId());
                        gRecordGameDAO.updateOccupyGameEndNew(gamePO.getId());
                    }
                } else {
                    gRecordGameDAO.updateGameEnd(gamePO.getId());
                }
            }
            String checkGaming = param.getRoomId() + roomDevicePO.getPositionNo();
            Long gameId = baseUtilService.startGaming(checkGaming, currentUser.getUserId(), param.getRoomId(), roomDevicePO.getPositionNo());
            if (Objects.isNull(gameId)) {
                throw new ApiException("该机位有人在玩，请您更换新机位");
            }
            // 判断是否有正在挑战中的任务进行游戏关联
            if (roomPO.getRoomType().equals(RoomTypeEnum.push_coins.getCode())) {
                MRecordBattlePushCoinsPO latestBattle = mRecordBattlePushCoinsDAO.findLatestBattleByUserId(currentUser.getUserId());
                if (Objects.nonNull(latestBattle) && Objects.isNull(latestBattle.getGameId())) {
                    latestBattle.setGameId(gameId);
                    mRecordBattlePushCoinsDAO.updateById(latestBattle);
                }
            } else if (roomPO.getRoomType().equals(RoomTypeEnum.arcade_machine.getCode())) {
                MRecordBattleArcadeMachinePO latestBattle = mRecordBattleArcadeMachineDAO.findLatestBattleByUserId(currentUser.getUserId());
                if (Objects.nonNull(latestBattle) && Objects.isNull(latestBattle.getGameId())) {
                    latestBattle.setGameId(gameId);
                    mRecordBattleArcadeMachineDAO.updateById(latestBattle);
                }
            } else {
                MRecordBattleRecreationPO latestBattle = mRecordBattleRecreationDAO.findLatestBattleByUserId(currentUser.getUserId());
                if (Objects.nonNull(latestBattle) && Objects.isNull(latestBattle.getGameId())) {
                    latestBattle.setGameId(gameId);
                    mRecordBattleRecreationDAO.updateById(latestBattle);
                }
            }
        }
        return Result.success().data(Boolean.TRUE).build();
    }

    @Override
    public Result<Boolean> startBattle(StartBattleDTO param) {
        AppUser currentUser = ApiContext.getCurrentUser();
        LocalDate now = LocalDate.now();
        if (param.getRoomType().equals(RoomTypeEnum.push_coins.getCode())) {
            long battle = mRecordBattlePushCoinsDAO.countUserTodayBattle(currentUser.getUserId());
            if (battle >= 5) {
                return Result.failure().message("超过今日可挑战次数").build();
            }
            MRankBattlePushCoinsPO pushCoinsPO = mRankBattlePushCoinsDAO.findById(param.getBattleId());
            if (Objects.isNull(pushCoinsPO)) {
                return Result.failure().message("挑战榜单不存在").build();
            }
            MRecordBattlePushCoinsPO latestBattle = mRecordBattlePushCoinsDAO.findLatestBattleByUserId(currentUser.getUserId());
            if (Objects.nonNull(latestBattle) && latestBattle.getStatus().equals(BattleStatusEnum.battling.getCode())) {
                if (Objects.isNull(latestBattle.getGameId())) {
                    latestBattle.setStatus(BattleStatusEnum.failed.getCode());
                } else {
                    MRankBattlePushCoinsPO po = mRankBattlePushCoinsDAO.findById(latestBattle.getBattleId());
                    GRecordGamePO gamePO = gRecordGameDAO.findById(latestBattle.getGameId());
                    latestBattle.setPineNut(gamePO.getGetPineNut().intValue());
                    if (gamePO.getGetPineNut() >= po.getPineNut()) {
                        latestBattle.setStatus(BattleStatusEnum.unclaimed.getCode());
                    } else {
                        latestBattle.setStatus(BattleStatusEnum.failed.getCode());
                    }
                }
                mRecordBattlePushCoinsDAO.updateById(latestBattle);
            }
            MRecordBattlePushCoinsPO po = new MRecordBattlePushCoinsPO();
            po.setBattleId(param.getBattleId());
            po.setUserId(currentUser.getUserId());
            po.setBattleDate(now);
            po.setStatus(BattleStatusEnum.battling.getCode());
            mRecordBattlePushCoinsDAO.save(po);
        } else if (param.getRoomType().equals(RoomTypeEnum.arcade_machine.getCode())) {
            long battle = mRecordBattleArcadeMachineDAO.countUserTodayBattle(currentUser.getUserId());
            if (battle >= 5) {
                return Result.failure().message("超过今日可挑战次数").build();
            }
            MRankBattleArcadeMachinePO machinePO = mRankBattleArcadeMachineDAO.findById(param.getBattleId());
            if (Objects.isNull(machinePO)) {
                return Result.failure().message("挑战榜单不存在").build();
            }
            MRecordBattleArcadeMachinePO latestBattle = mRecordBattleArcadeMachineDAO.findLatestBattleByUserId(currentUser.getUserId());
            if (Objects.nonNull(latestBattle) && latestBattle.getStatus().equals(BattleStatusEnum.battling.getCode())) {
                if (Objects.isNull(latestBattle.getGameId())) {
                    latestBattle.setStatus(BattleStatusEnum.failed.getCode());
                } else {
                    MRankBattleArcadeMachinePO po = mRankBattleArcadeMachineDAO.findById(latestBattle.getBattleId());
                    GRecordGamePO gamePO = gRecordGameDAO.findById(latestBattle.getGameId());
                    latestBattle.setPineNut(gamePO.getGetPineNut().intValue());
                    if (gamePO.getGetPineNut() >= po.getPineNut()) {
                        latestBattle.setStatus(BattleStatusEnum.unclaimed.getCode());
                    } else {
                        latestBattle.setStatus(BattleStatusEnum.failed.getCode());
                    }
                }
                mRecordBattleArcadeMachineDAO.updateById(latestBattle);
            }
            MRecordBattleArcadeMachinePO po = new MRecordBattleArcadeMachinePO();
            po.setBattleId(param.getBattleId());
            po.setUserId(currentUser.getUserId());
            po.setBattleDate(now);
            po.setStatus(BattleStatusEnum.battling.getCode());
            mRecordBattleArcadeMachineDAO.save(po);
        } else {
            long battle = mRecordBattleRecreationDAO.countUserTodayBattle(currentUser.getUserId());
            if (battle >= 5) {
                return Result.failure().message("超过今日可挑战次数").build();
            }
            MRankBattleRecreationPO recreationPO = mRankBattleRecreationDAO.findById(param.getBattleId());
            if (Objects.isNull(recreationPO)) {
                return Result.failure().message("挑战榜单不存在").build();
            }
            MRecordBattleRecreationPO latestBattle = mRecordBattleRecreationDAO.findLatestBattleByUserId(currentUser.getUserId());
            if (Objects.nonNull(latestBattle) && latestBattle.getStatus().equals(BattleStatusEnum.battling.getCode())) {
                if (Objects.isNull(latestBattle.getGameId())) {
                    latestBattle.setStatus(BattleStatusEnum.failed.getCode());
                } else {
                    MRankBattleRecreationPO po = mRankBattleRecreationDAO.findById(latestBattle.getBattleId());
                    GRecordGamePO gamePO = gRecordGameDAO.findById(latestBattle.getGameId());
                    latestBattle.setPineNut(gamePO.getGetPineNut().intValue());
                    if (gamePO.getGetPineNut() >= po.getPineNut()) {
                        latestBattle.setStatus(BattleStatusEnum.unclaimed.getCode());
                    } else {
                        latestBattle.setStatus(BattleStatusEnum.failed.getCode());
                    }
                }
                mRecordBattleRecreationDAO.updateById(latestBattle);
            }
            MRecordBattleRecreationPO po = new MRecordBattleRecreationPO();
            po.setBattleId(param.getBattleId());
            po.setUserId(currentUser.getUserId());
            po.setBattleDate(now);
            po.setStatus(BattleStatusEnum.battling.getCode());
            mRecordBattleRecreationDAO.save(po);
        }

        //完成每日任务
        String dailyKey = currentUser.getUserId() + now.toString() + "dailyTask";
        baseUtilService.setDailyTask(dailyKey, currentUser.getUserId(), now);
        mRecordTaskDailyDAO.updateFirstBattle(currentUser.getUserId(), now);
        baseUtilService.dealDailyTaskAllComplete(currentUser.getUserId(), now);
        return Result.success().data(Boolean.TRUE).build();
    }

    @Override
    public Result<Boolean> checkPushCoins(Long roomId, Integer count) {
        AppUser currentUser = ApiContext.getCurrentUser();
        GConfRoomPO roomPO = gConfRoomDAO.findById(roomId);
        GRecordGamePO gamePO = gRecordGameDAO.findLatestGaming(roomId, currentUser.getUserId());
        if (Objects.nonNull(gamePO) && Objects.nonNull(gamePO.getRecordOccupyId())) {
            MRecordOccupyPO recordOccupyPO = mRecordOccupyDAO.findById(gamePO.getRecordOccupyId());
            if (roomPO.getMultipleValue() * count <= recordOccupyPO.getCurrentPinecone()) {
                return Result.success().data(Boolean.TRUE).build();
            } else {
                return Result.success().data(Boolean.FALSE).build();
            }
        } else {
            UAppUserEquityPO equityPO = uAppUserEquityDAO.findOne(UAppUserEquityPO::getUserId, currentUser.getUserId());
            if (roomPO.getMultipleValue() * count <= equityPO.getPinecone()) {
                return Result.success().data(Boolean.TRUE).build();
            } else {
                return Result.success().data(Boolean.FALSE).build();
            }
        }
    }

    @Override
    public Result<PlayPineDataVO> findPlayPinecone(Long roomId) {
        PlayPineDataVO vo = new PlayPineDataVO();
        AppUser currentUser = ApiContext.getCurrentUser();
        UAppUserEquityPO equityPO = uAppUserEquityDAO.findOne(UAppUserEquityPO::getUserId, currentUser.getUserId());
        GRecordGamePO gamePO = gRecordGameDAO.findLatestGaming(roomId, currentUser.getUserId());
        if (Objects.nonNull(gamePO) && Objects.nonNull(gamePO.getRecordOccupyId())) {
            MRecordOccupyPO recordOccupyPO = mRecordOccupyDAO.findById(gamePO.getRecordOccupyId());
            vo.setOccupyPinecone(recordOccupyPO.getCurrentPinecone());
        }
        vo.setPinecone(equityPO.getPinecone());
        vo.setPineNut(equityPO.getPineNut());
        return Result.success().data(vo).build();
    }

    @Override
    public Result<Boolean> reportRepair(BaseRoomIdDTO param) throws IOException {
        GConfRoomPO roomPO = gConfRoomDAO.findById(param.getRoomId());
        if (Objects.isNull(roomPO)) {
            return Result.failure().message("房间不存在").build();
        }
        if (!roomPO.getRoomType().equals(RoomTypeEnum.push_coins.getCode())) {
            return Result.failure().message("只有推币机房间可以报修").build();
        }
        AppUser currentUser = ApiContext.getCurrentUser();
        LocalDateTime now = LocalDateTime.now();
        GConfRoomDevicePO roomDevicePO = gConfRoomDeviceDAO.findOne(GConfRoomDevicePO::getRoomId, roomPO.getId());
        GConfDevicePO devicePO = gConfDeviceDAO.findOne(GConfDevicePO::getId, roomDevicePO.getDeviceId());
        if (Objects.isNull(devicePO.getRepairTime())) {
            gConfDeviceDAO.updateDeviceRepair(devicePO.getId(), now);
            GRoomRepairRecordPO repairRecordPO = new GRoomRepairRecordPO();
            repairRecordPO.setUserId(currentUser.getUserId());
            repairRecordPO.setRoomId(roomDevicePO.getRoomId());
            repairRecordPO.setDeviceId(devicePO.getId());
            repairRecordPO.setRoomName(roomPO.getRoomName());
            repairRecordPO.setRoomType(roomPO.getRoomType());
            repairRecordPO.setStatus(RepairStatusEnum.repairing.getCode());
            gRoomRepairRecordDAO.save(repairRecordPO);
            List<MRecordProductLookPO> lookPOS = mRecordProductLookDAO.findAllNormalNoEndByRoom(roomDevicePO.getRoomId());
            lookPOS.forEach(po -> {
                long minutesBetween = ChronoUnit.MINUTES.between(po.getEndTime(), now);
                mRecordProductLookDAO.updateRepair(po.getId(), (int) minutesBetween);
            });
            List<MRecordOccupyPO> occupyPOS = mRecordOccupyDAO.findAllNormalNoEndByRoom(roomDevicePO.getRoomId());
            occupyPOS.forEach(po -> {
                long minutesBetween = ChronoUnit.MINUTES.between(po.getEndTime(), now);
                mRecordOccupyDAO.updateRepair(po.getId(), (int) minutesBetween);
            });
            BackedMessage backedMessage = new BackedMessage();
            backedMessage.setId(param.getRoomId());
            backedMessage.setTitle(roomPO.getRoomName());
            backedMessage.setStatus("待维修");
            backedMessage.setMsgTime(LocalDateTimeUtil.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"));
            messageProducer.sendMessage(MQTTTopicConstant.REPORT_REPAIR, JSON.toJSONString(backedMessage));
        }
        return Result.success().data(Boolean.TRUE).build();
    }

    @Override
    public Result<AutoVO> findAutoInfo(Long roomId) {
        GConfRoomPO roomPO = gConfRoomDAO.findById(roomId);
        if (Objects.isNull(roomPO)) {
            return Result.failure().message("房间不存在").build();
        }
        AppUser currentUser = ApiContext.getCurrentUser();
        GRecordGamePO gamePO = gRecordGameDAO.findLatestGaming(roomId, currentUser.getUserId());
        AutoVO vo = new AutoVO();
        if (Objects.nonNull(gamePO) && Objects.nonNull(gamePO.getRecordOccupyId())) {
            MRecordOccupyPO recordOccupyPO = mRecordOccupyDAO.findById(gamePO.getRecordOccupyId());
            int unitPinecone;
            if (roomPO.getRoomType().equals(RoomTypeEnum.push_coins.getCode())) {
                unitPinecone = Math.multiplyExact(roomPO.getMultipleValue(), 4);
            } else {
                unitPinecone = Math.multiplyExact(roomPO.getMultipleValue(), 12);
            }
            int maxTime = recordOccupyPO.getCurrentPinecone() / unitPinecone;
            vo.setPinecone(recordOccupyPO.getCurrentPinecone());
            vo.setUnitPinecone(unitPinecone);
            vo.setMaxTime(maxTime);
        } else {
            UAppUserEquityPO equityPO = uAppUserEquityDAO.findOne(UAppUserEquityPO::getUserId, currentUser.getUserId());
            int unitPinecone;
            if (roomPO.getRoomType().equals(RoomTypeEnum.push_coins.getCode())) {
                unitPinecone = Math.multiplyExact(roomPO.getMultipleValue(), 4);
            } else {
                unitPinecone = Math.multiplyExact(roomPO.getMultipleValue(), 12);
            }
            int maxTime = equityPO.getPinecone() / unitPinecone;
            vo.setPinecone(equityPO.getPinecone());
            vo.setUnitPinecone(unitPinecone);
            vo.setMaxTime(maxTime);
        }
        return Result.success().data(vo).build();
    }

    @Override
    public Result<List<PrizeConfigVO>> findPrizeConfig(Long roomId) {
        GConfRoomPO roomPO = gConfRoomDAO.findById(roomId);
        if (Objects.isNull(roomPO)) {
            return Result.failure().message("房间不存在").build();
        }
        if (!roomPO.getRoomType().equals(RoomTypeEnum.push_coins.getCode())) {
            return Result.failure().message("只有推币机房间可以赏金").build();
        }
        List<GConfRoomPrizePO> pos = gConfRoomPrizeDAO.findList(GConfRoomPrizePO::getRoomId, roomId);
        List<PrizeConfigVO> result = new ArrayList<>();
        pos.forEach(po -> {
            PrizeConfigVO vo = new PrizeConfigVO();
            vo.setPrizeType(po.getPrizeType());
            List<GConfPrizeItemPO> itemPOS = gConfPrizeItemDAO.findList(GConfPrizeItemPO::getPrizeId, po.getPrizeId());
            List<PrizeItemVO> itemVOS = ListUtil.copyList(itemPOS, PrizeItemVO.class);
            vo.setItemVOS(itemVOS);
            result.add(vo);
        });
        return Result.success().data(result).build();
    }

    @Override
    public Result<Boolean> submitPrize(SubmitPrizeDTO param) throws IOException {
        GConfRoomPO roomPO = gConfRoomDAO.findById(param.getRoomId());
        if (Objects.isNull(roomPO)) {
            return Result.failure().message("房间不存在").build();
        }
        if (!roomPO.getRoomType().equals(RoomTypeEnum.push_coins.getCode())) {
            return Result.failure().message("只有推币机房间可以赏金").build();
        }
        GConfPrizeItemPO itemPO = gConfPrizeItemDAO.findById(param.getId());
        if (Objects.isNull(itemPO)) {
            return Result.failure().message("奖项不存在").build();
        }
        GConfRoomPrizePO roomPrizePO = gConfRoomPrizeDAO.findOnePrize(roomPO.getId(), itemPO.getPrizeId());
        if (Objects.isNull(roomPrizePO)) {
            return Result.failure().message("该奖项不属于此房间").build();
        }
        AppUser currentUser = ApiContext.getCurrentUser();
        UAppUserPO userPO = uAppUserDAO.findById(currentUser.getUserId());
        GRecordPrizePO po = new GRecordPrizePO();
        po.setUserId(currentUser.getUserId());
        po.setRoomId(roomPO.getId());
        po.setRoomName(roomPO.getRoomName());
        po.setRoomType(roomPO.getRoomType());
        po.setImage(param.getImage());
        po.setPrizeType(itemPO.getItemName());
        po.setPrizePinecone(itemPO.getItemValue());
        po.setStatus(PrizeStatusEnum.pending_approval.getCode());
        gRecordPrizeDAO.save(po);
        BackedMessage backedMessage = new BackedMessage();
        backedMessage.setId(currentUser.getUserId());
        backedMessage.setTitle(userPO.getNickname());
        backedMessage.setStatus("待审批");
        backedMessage.setDesc(itemPO.getItemName());
        backedMessage.setMsgTime(LocalDateTimeUtil.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"));
        messageProducer.sendMessage(MQTTTopicConstant.PRIZE_CHECK, JSON.toJSONString(backedMessage));
        return Result.success().data(Boolean.TRUE).build();
    }

    @Override
    public Result<List<CwPrizeConfigVO>> findCwPrizeConfig() {
        List<CwPrizeConfigVO> list = new ArrayList<>();
        List<GConfPrizePO> prizePOS = gConfPrizeDAO.findList(GConfPrizePO::getPrizeType, PrizeTypeEnum.critical_strike.getCode(), GConfPrizePO::getMultipleType);
        prizePOS.forEach(po -> {
            CwPrizeConfigVO vo = new CwPrizeConfigVO();
            vo.setMultipleType(po.getMultipleType());
            List<GConfPrizeItemPO> itemPOS = gConfPrizeItemDAO.findList(GConfPrizeItemPO::getPrizeId, po.getId(), GConfPrizeItemPO::getScore);
            List<PrizeItemVO> itemVOS = ListUtil.copyList(itemPOS, PrizeItemVO.class);
            vo.setItemVOS(itemVOS);
            list.add(vo);
        });
        return Result.success().data(list).build();
    }

    @Override
    public Result<List<PrizeRecordVO>> findCwRecord() {
        List<PrizeRecordVO> list = new ArrayList<>();
        List<GRecordPrizePO> pos = gRecordPrizeDAO.findNewMachine(null);
        pos.forEach(po -> {
            PrizeRecordVO vo = new PrizeRecordVO();
            BeanUtils.copyProperties(po, vo);
            UAppUserPO userPO = uAppUserDAO.findById(po.getUserId());
            UAppUserEquityPO equityPO = uAppUserEquityDAO.findOne(UAppUserEquityPO::getUserId, po.getUserId());
            vo.setNickname(userPO.getNickname());
            vo.setAvatarurl(userPO.getAvatarurl());
            vo.setVipGrade(equityPO.getVipGrade());
            list.add(vo);
        });
        return Result.success().data(list).build();
    }

    @Override
    public Result<List<BasePrizeRecordVO>> findMyCwRecord() {
        AppUser currentUser = ApiContext.getCurrentUser();
        List<GRecordPrizePO> pos = gRecordPrizeDAO.findNewMachine(currentUser.getUserId());
        List<BasePrizeRecordVO> list = ListUtil.copyList(pos, BasePrizeRecordVO.class);
        return Result.success().data(list).build();
    }

    @Override
    public Result<Long> getLookPersonCount(Long roomId) {
        long lookPersonCount = gRecordRoomWatchDAO.getLookPersonCount(roomId);
        return Result.success().data(lookPersonCount).build();
    }

    @Override
    public Result<Long> getTotalPineNut(Long roomId) {
        AppUser currentUser = ApiContext.getCurrentUser();
        GConfRoomPO roomPO = gConfRoomDAO.findById(roomId);
        if (Objects.isNull(roomPO)) {
            return Result.failure().message("房间不存在").build();
        }
        GRecordGamePO gamePO = gRecordGameDAO.findLatestGaming(roomPO.getId(), currentUser.getUserId());
        if (Objects.nonNull(gamePO)) {
            if (Objects.isNull(gamePO.getRecordOccupyId())) {
                return Result.success().data(gamePO.getGetPineNut()).build();
            } else {
                MRecordOccupyPO occupyPO = mRecordOccupyDAO.findById(gamePO.getRecordOccupyId());
                return Result.success().data(occupyPO.getCurrentPinecone()).build();
            }
        }
        return Result.success().data(null).build();
    }

    @Override
    public Result<PlayGetDataVO> getTotalPineNutNew(Long roomId) {
        AppUser currentUser = ApiContext.getCurrentUser();
        GConfRoomPO roomPO = gConfRoomDAO.findById(roomId);
        if (Objects.isNull(roomPO)) {
            return Result.failure().message("房间不存在").build();
        }
        PlayGetDataVO vo = new PlayGetDataVO();
        GRecordGamePO gamePO = gRecordGameDAO.findLatestGaming(roomPO.getId(), currentUser.getUserId());
        if (Objects.nonNull(gamePO)) {
            if (Objects.isNull(gamePO.getRecordOccupyId())) {
                vo.setPineData(gamePO.getGetPineNut().intValue());
                vo.setOccupying(Boolean.FALSE);
            } else {
                MRecordOccupyPO occupyPO = mRecordOccupyDAO.findById(gamePO.getRecordOccupyId());
                vo.setPineData(occupyPO.getCurrentPinecone());
                vo.setOccupying(Boolean.TRUE);
                vo.setDuration(occupyPO.getDuration());
            }
            return Result.success().data(vo).build();
        }
        return Result.success().data(vo).build();
    }
}
